//
//  MYGSocketManager.swift
//  MYGrow
//
//  Created by 小火科技 on 2024/3/11.
//

import UIKit
import Starscream
import HandyJSON

class MYGSocketManager {
    static let shared = MYGSocketManager()
    
    private(set) var user: MYGIMModel?
    
    private(set) var totalMessage: MYGIMMessageListModel?
    
    private var socket: WebSocket?
    
    private var timer: Timer?
    
    var chatModel: MYGUserInfoChatModel?
    
    private(set) var isConnected: Bool = false {
        didSet {
            if isConnected != oldValue && isConnected {
                login()
            }
        }
    }
    func connect() {
        // https://im-dev.medataplus.com/           wss://yihuanim.weincloud.com:2088
        var request = URLRequest(url: URL(string: "wss://im-dev.medataplus.com:2088")!)
        request.timeoutInterval = 5
        socket = WebSocket(request: request)
        socket?.delegate = self
        socket?.connect()
    }
    func disconnect() {
        if isConnected {
            socket!.disconnect()
            socket = nil
            isConnected = false
        }
    }
    
    func reContent(){
        if isConnected == true {
            return
        }
        DispatchQueue.main.asyncAfter(delay: 0.5) {[self] in
            connect()
        }
       
    }
}

extension MYGSocketManager: WebSocketDelegate {
    func didReceive(event: WebSocketEvent, client: WebSocketClient) {
        switch event {
        case .connected(let headers):
            print("websocket is connected: \(headers)")
            
            if let timer = self.timer {
                timer.invalidate()
                self.timer = nil
            }
            
            let time = Timer.init(timeInterval: 5, repeats: true) {[weak self] _ in
                self?.sendPing()
            }
            RunLoop.current.add(time, forMode: .common)
            self.timer = time
        case .disconnected(let reason, let code):
            isConnected = false
            print("websocket is disconnected: \(reason) with code: \(code)")
        case .text(let string):
            dealMessage(string)
            print("接收到的数据 Received text: \(string)")
        case .binary(let data):
            print("Received data: \(data.count)")
        case .ping(_):
            break
        case .pong(_):
            break
        case .viabilityChanged(_):
            break
        case .reconnectSuggested(_):
            break
        case .cancelled:
            isConnected = false
        case .error(let error):
            isConnected = false
            connect()
//            handleError(error)
            case .peerClosed:
                   break
        }
    }
    
    private func login() {
        
        // 获取token
        MYGNetwork<MYGSocketAPI,MYGUserInfoChatModel>.request(target: .getLoginToken) {[self] item in
//            guard let item = item else {
//                return
//            }
            self.chatModel = item
            guard let data = packetMessage(c: "ImBase", a: "login", model: MYGIMLoginSendModel()) else {
                return
            }
            socket?.write(data: data, completion: nil)
            
        } failed: {  _, error in
            MYGLoading.hide()
            MMYGHUD.showToast(text: error)
        }
    
    }
        
     func getMessageList() {
        guard let data = packetMessage(c: "User", a: "loadSessionList", model: MYGIMMessageListSendModel()) else {
            return
        }
        
        socket?.write(data: data, completion: nil)
    }
    
    func getSingleChatMessage(_ sessionId: Int, page: Int = 1) {
        let model = MYGIMSinglePageSendModel()
        model.session_id = sessionId
        model.page = page
        guard let data = packetMessage(c: "User", a: "loadSession", model: model) else {
            return
        }
        
        socket?.write(data: data, completion: nil)
    }
    
    //创建会话 与医生聊天加1 和患者聊天加2
    func createDcotorChat(mobile: String) {
        let model = MYGDoctorSendModel()
        model.mobile = mobile
        model.type = "user"
        guard let data = packetMessage(c: "Message", a: "OpenSession", model: model) else {
            return
        }
        
        socket?.write(data: data, completion: nil)
    }
    
    private func sendPing() {
        socket?.write(string: "{\"c\":\"ImBase\",\"a\":\"ping\"}", completion: nil)
    }
    
    func drawMessage(_ type: MYGIMMessageType, sessionId: Int, localId: Int, messageId: Int) {
        let model = MYGWithdrawSendModel()
        model.type = type
        model.session_id = sessionId
        model.localhost_id = localId
//        model.message_id = messageId
        guard let data = packetMessage(c: "Message", a: "backMessage", model: model, date: model.localhost_id) else {
            return
        }
        
        socket?.write(data: data, completion: nil)
    }
    
    func addTemplate(_ text: String, id: Int, sessionId: Int, isAdd: Bool) {
       let model = MYGIMChatTemplateSendModel()
        model.action = !isAdd ? "edit" : "add"
        model.id = isAdd ? 1 : id
        model.message_content = text
        model.session_id = sessionId
        guard let data = packetMessage(c: "User", a: "set_fastmessage", model: model) else {
            return
        }

        socket?.write(data: data, completion: nil)
    }
    
    func deleteTemplate(id: Int, sessionId: Int) {
       let model = MYGIMChatTemplateSendModel()
        model.action = "delete"
        model.id = id
        model.session_id = sessionId
        guard let data = packetMessage(c: "User", a: "set_fastmessage", model: model) else {
            return
        }

        socket?.write(data: data, completion: nil)
    }
}

// MARK: - 接收信息
extension MYGSocketManager {
    private func dealMessage(_ text: String) {
        guard let model = MYGIMBaseModel.deserialize(from: text.dic) else { return }
        guard let type = model.type else { return }
        switch type {
        case .open:
            isConnected = true
        case .login:
            let model = MYGIMModel.deserialize(from: model.data as? [String: Any])
            user = model
            getMessageList()
        case .list:
            let model = MYGIMMessageListModel.deserialize(from: model.data as? [String: Any])
            self.totalMessage = model
            
            DispatchQueue.main.async {
                NotificationCenter.default.post(name: NSNotification.Name.init("MYGIMMessageList"), object: nil)
            }
        case .single:
            guard let params = model.data as? [String: Any], let model = MYGIMSingleChatModel.deserialize(from: params) else {
                return
            }
            
            DispatchQueue.main.async {
                NotificationCenter.default.post(name: NSNotification.Name.init("MYGIMMessageDetail"), object: nil, userInfo: params)
            }
            
        case .newMessage:
            guard let params = model.data as? [String: Any], let session = params["sessionInfo"] as? [String: Any], let model = MYGIMMessageListDetailModel.deserialize(from: session) else {
                return
            }
            
            DispatchQueue.main.async {
                NotificationCenter.default.post(name: NSNotification.Name.init("MYGIMMessageDetailNew"), object: model.id, userInfo: params)
            }
            
            getMessageList()
        case .readMessage:
            guard let params = model.data as? [String: Any], let id = Int(params["session_id"] as? String ?? "") else { return }
            
            DispatchQueue.main.async {
                NotificationCenter.default.post(name: NSNotification.Name.init("MYGIMMessageRead"), object: id, userInfo: params)
            }
            getMessageList()
        case .drawMessage:
            guard let params = model.data as? [String: Any], let session = params["sessionInfo"] as? [String: Any], let model = MYGIMMessageListDetailModel.deserialize(from: session) else {
                return
            }
            DispatchQueue.main.async {
                NotificationCenter.default.post(name: NSNotification.Name.init("MYGIMMessageDraw"), object: model.id, userInfo: params)
            }
            getMessageList()
        case .fastMessage:
            guard let params = model.data as? [String: Any] else {
                return
            }
            DispatchQueue.main.async {
                NotificationCenter.default.post(name: NSNotification.Name.init("MYGIMMessageTemplate"), object: nil, userInfo: params)
            }
        case .readApply:
            guard let params = model.data as? [String: Any], let session = params["messageData"] as? [String: Any], let model = MYGIMReadApplyChatData.deserialize(from: session) else {
                return
            }
            DispatchQueue.main.async {
                NotificationCenter.default.post(name: NSNotification.Name.init("MYGIMMessageReadApply"), object:model.id ,userInfo:params)
            }
        case .openSession:
            guard let params = model.data as? [String: Any] else {
                return
            }
            DispatchQueue.main.async {
                NotificationCenter.default.post(name: NSNotification.Name.init("MYGIMMessageSession"), object: nil, userInfo: params)
            }
        case .showMsg:
            guard let params = model.data as? [String: Any] else {
                return
            }
            DispatchQueue.main.async {
                NotificationCenter.default.post(name: NSNotification.Name.init("MYGIMShowMessage"), object: nil, userInfo: params)
            }
        case .loginFail:
            isConnected = false
            reContent()
        }
    }
}

// MARK: - 聊天
extension MYGSocketManager {
    func sendTextMessage(_ text: String, sessionId: Int, is_destruction: Int, date: Int) {
        let model = MYGIMMessageSendTextModel()
        model.message = text
        model.session_id = sessionId
        model.is_destruction = is_destruction
        guard let data = packetMessage(c: "Message", a: "sendMessage", model: model, date: date) else {
            return
        }
        
        socket?.write(data: data, completion: nil)
        
        getMessageList()
    }
    
    func sendImageMessage(_ text: String, sessionId: Int, is_destruction: Int, date: Int) {
        let model = MYGIMMessageSendTextModel()
        model.message = text
        model.session_id = sessionId
        model.type = .image
        model.is_destruction = is_destruction
        
        guard let data = packetMessage(c: "Message", a: "sendMessage", model: model, date: date) else {
            return
        }
        
        socket?.write(data: data, completion: nil)
        
        getMessageList()
    }
    
    func sendVoiceMessage(_ text: String, duration: Int, sessionId: Int, is_destruction: Int, date: Int) {
        let model = MYGIMMessageSendVoiceModel()
        model.message.voiceUrl = text
        model.message.time = duration
        model.session_id = sessionId
        model.type = .voice
        model.is_destruction = is_destruction
        
        guard let data = packetMessage(c: "Message", a: "sendMessage", model: model, date: date) else {
            return
        }
        
        socket?.write(data: data, completion: nil)
        
        getMessageList()
    }
    
    func sendPositionMessage(_ item: MYGIMMessageSendPositionModelPosition, sessionId: Int, date: Int) {
        let model = MYGIMMessageSendPositionModel()
        model.message = item
        model.session_id = sessionId
        
        guard let data = packetMessage(c: "Message", a: "sendMessage", model: model, date: date) else {
            return
        }
        
        socket?.write(data: data, completion: nil)
        
        getMessageList()
    }
    
    func sendReportMessage(_ text: String,type: MYGIMMessageType, sessionId: Int, is_destruction: Int, date: Int) {
        
        let model = MYGIMMessageSendTextModel()
        model.message = text
        model.session_id = sessionId
        model.is_destruction = is_destruction
        model.type = type
        guard let data = packetMessage(c: "Message", a: "sendMessage", model: model, date: date,fixDate: "\(type.applyIndex)") else {
            return
        }
        
        socket?.write(data: data, completion: nil)
        
        getMessageList()
    }
    
    func fireMessage(_ sessionId: Int, _ hostId: Int) {
        let model = MYGIMFireMessageReadModel()
        model.localhost_id = hostId
        model.session_id = sessionId
        
        guard let data = packetMessage(c: "User", a: "read_destruction", model: model, date: model.localhost_id) else {
            return
        }
        
        socket?.write(data: data, completion: nil)
        
        getMessageList()
    }
}

// MARK: - 包装数据
extension MYGSocketManager {
    private func packetMessage<T: HandyJSON>(c: String, a: String, model: T, date: Int = Int(Date().timeIntervalSince1970), fixDate:String = "") -> Data? {
        let item = MYGIMSendModel()
        item.c = c
        item.a = a
        var params = item.toJSON()
        
        let tokenModel = MYGIMSendTokenModel()
        tokenModel.auth_token = (self.chatModel?.userinfo.auth_token)!  //"7|864000|1712368716|6e9f487031a3be612af29a45f92f4899"
        tokenModel.im_tourists_token = (self.chatModel?.userinfo.token)!//"7|864000|1712368716|94396adfc3bab612e072217948575e49"
        
        var data = model.toJSON()
        if fixDate.isEmpty {
            data?["localhost_id"] = date
        }else {
            data?["localhost_id"] = "\(date)\(fixDate)"
        }
        data?["tokens"] = tokenModel.toJSON()
        params?["data"] = data
        
        guard let params = params, let data = try? JSONSerialization.data(withJSONObject: params) else { return nil }
        
        print("发送数据：-------------------")
        print(params.jsonString() ?? "")
        print("-------------------")
        return data
    }
}
